Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not allocate more resources than the maxTotal #394

Merged
merged 4 commits into from
Jun 11, 2022

Conversation

iRevive
Copy link
Contributor

@iRevive iRevive commented Jun 7, 2022

My attempt to fix #389.

I assume, maxPerKey should behave in the same way?

Copy link
Member

@rossabaker rossabaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks right to me.

I wonder whether it obsoletes this check? The old behavior was that the setting enforced a max idle. But if we can't go above the max at any point, we can't have more than the max idling. The check could be useful for a renamed property, maxIdle, which I think would be in harmony with how commons-pool2 works.

Copy link
Member

@rossabaker rossabaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@iRevive
Copy link
Contributor Author

iRevive commented Jun 8, 2022

@rossabaker

Unfortunately, I do not see a simple way of testing maxIdle until the PoolStats gets extended.
I guess the test coverage can be improved once #127 is done.

@iRevive
Copy link
Contributor Author

iRevive commented Jun 8, 2022

Currently, I have a bit of spare time and I can work on some improvements:

I assume this work can be scheduled for 0.5.x release?

@rossabaker
Copy link
Member

I would like to eventually integrate this with otel4s. It would be interesting to have an introspectable backend for metrics.

@iRevive
Copy link
Contributor Author

iRevive commented Jun 8, 2022

I was keeping an eye on otel4s for a while. I can experiment with it within keypool.

@rossabaker
Copy link
Member

That would be fantastic! Regarding 0.4 vs. 0.5, we're in that weird "early semver" territory.

  • If we go 0.5, we can break binary compatibility... but then can't use the improvements in http4s-0.23, which I think is by far our most prominent use.
  • Or we can go 0.5 and keep compatibility with 0.4. That minor bump better expresses new features, but would still work with our major client. Since we made a semantic change to maxTotal, that's probably justified, even if we did preserve binary compatibility.

Wherever this change lands, we need to shout about it in the release notes and in the http4s release notes, but I also think it's important enough it needs to be out there.

@rossabaker
Copy link
Member

I'm still not sure whether this is an 0.4 or 0.5. I'm inclined toward it being a bugfix and continuing to call this 0.4.

@rossabaker rossabaker requested a review from a team June 9, 2022 17:23
Copy link
Member

@danicheg danicheg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a third-party guy at keypool mostly, but this LGTM.

@@ -402,6 +416,7 @@ object KeyPool {
val defaultReuseState = Reusable.Reuse
val idleTimeAllowedInPool = 30.seconds
def maxPerKey[K](k: K): Int = Function.const(100)(k)
val maxIdle = 100
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have maxIdle equal to maxTotal always?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

Basically, the rule should be this one: maxIdle <= maxTotal

So the builder method can be defined as the following:

def withMaxTotal(total: Int) = 
  copy(maxTotal = total, maxIdle = math.min(maxIdle, total))

Should withMaxIdle throw an exception when maxIdle > maxTotal?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commons-pool2 has three independent settings: maxTotal, maxIdle, and minIdle.

  • maxTotal is how many you can handle in a burst
  • maxIdle and minIdle let you tune how many you can afford to keep warm in order to usually have one ready under normal load

minIdle <= maxIdle <= maxTotal ought to always be true. minIdle == maxIdle == maxTotal will tend to be true when creating them is expensive and idling them is cheap.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In an ideal world, I would expect a builder to have validation logic under the hood.
Neither negative maxTotal nor maxIdle makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be surprising to me if withMaxTotal implemented the math.min. Imagine reading from a config, and withMaxTotal got called before withMaxIdle.

I can imagine implementing math.min at creation time, logging a warning (http4s-blaze does this with timeout values), or raising an error.

# Conflicts:
#	core/src/main/scala/org/typelevel/keypool/KeyPool.scala
#	core/src/main/scala/org/typelevel/keypool/KeyPoolBuilder.scala
@rossabaker
Copy link
Member

This is major forward progress and shouldn't be blocked by validations. Configuring maxIdle > maxTotal is wrong, but harmless: we'll just never hit that many. We can add a warning, or validate non-negative, but that can be a separate PR.

@rossabaker rossabaker merged commit 4b55f4a into typelevel:main Jun 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pool allows borrowing more resources than allowed
3 participants